<?php

class Release extends DBObject {

    public $table = 'mtl.releases';
    const table_static = 'mtl.releases';
    public $sequence = 'mtl.releases_id';
    const sequence_static = 'mtl.releases_id';

    public $_year_started;
    public $_year_finished;
    public $_release_date;
    public $_schedule_date;
    public $_track_count;
    public $_length;
    public $_tba;
    public $_has_picture;
    public $_record_type;
    public $_record_type_id;
    public $_picture_path;
    public $_leaked;

    public $_artist_name; // readonly
    public $_label_name; // readonly
    public $_wiki; // readonly
    

    public static function getById($id) {

        return parent::getById($id, __CLASS__);
    }

    public static function getByName($name) {

        return parent::getByName($name, __CLASS__);
    }

    public function load() {

        parent::load();

        $res = $this->dbo->getRow("SELECT
            r.name,
            r.year_started,
            r.year_finished,
            r.release_date,
            r.schedule_date,
            r.track_count,
            r.length,
            r.tba,
            r.has_picture,
            r.record_type_id,
            r.leaked,
            rt.name as record_type,
            r.picture_path,
            a.name as artist_name,
            l.name as label_name
            FROM $this->table r
            LEFT JOIN mtl.record_types rt ON (rt.id = r.record_type_id)
            LEFT JOIN mtl.artists_rel_release rel ON (rel.release_id = r.id)
            LEFT JOIN mtl.artists a ON (a.id = rel.artist_id)
            LEFT JOIN mtl.releases_rel_label rel2 ON (rel2.release_id = r.id)
            LEFT JOIN mtl.labels l ON (l.id = rel2.label_id)
            WHERE r.id=?",
            array(
                DBInteger::create($this->id)
            ),
            DB_FETCHMODE_ASSOC
        );

        throwOnError($res);

        if(empty($res))
            throw new Exception(_('Failed to load release.'));

        $this->name = DBString::create($res['name']);
        $this->year_started = DBYear::create($res['year_started']);
        $this->year_finished = DBYear::create($res['year_finished']);
        $this->release_date = DBDate::create($res['release_date']);
        $this->schedule_date = DBString::create($res['schedule_date']);
        $this->track_count = DBTrackCount::create($res['track_count']);
        $this->length = DBLength::create($res['length']);
        $this->tba = DBBoolean::create($res['tba']);
        $this->has_picture = DBBoolean::create($res['has_picture']);
        $this->record_type = DBString::create($res['record_type']);
        $this->record_type_id = DBInteger::create($res['record_type_id']);
        $this->picture_path = DBString::create($res['picture_path']);
        $this->artist_name = DBString::create($res['artist_name']);
        $this->label_name = DBString::create($res['label_name']);
        $this->leaked = DBBoolean::create($res['leaked']);

        return true;
    }

    public function loadByName() {

        parent::loadByName();

        $res = $this->dbo->getRow("SELECT
            r.id,
            r.year_started,
            r.year_finished,
            r.release_date,
            r.schedule_date,
            r.track_count,
            r.length,
            r.tba,
            r.has_picture,
            r.record_type_id,
            r.leaked,
            rt.name as record_type,
            r.picture_path,
            a.name as artist_name,
            l.name as label_name
            FROM $this->table r
            LEFT JOIN mtl.record_types rt ON (rt.id = r.record_type_id)
            LEFT JOIN mtl.artists_rel_release rel ON (rel.release_id = r.id)
            LEFT JOIN mtl.artists a ON (a.id = rel.artist_id)
            LEFT JOIN mtl.releases_rel_label rel2 ON (rel2.release_id = r.id)
            LEFT JOIN mtl.labels l ON (l.id = rel2.label_id)
            WHERE LOWER(name)=LOWER(?)",
            array(
                DBString::create($this->name)
            ),
            DB_FETCHMODE_ASSOC
        );

        throwOnError($res);

        if(empty($res))
            throw new Exception(_('Failed to load release.'));

        $this->id = DBInteger::create($res['id']);
        $this->year_started = DBYear::create($res['year_started']);
        $this->year_finished = DBYear::create($res['year_finished']);
        $this->release_date = DBDate::create($res['release_date']);
        $this->schedule_date = DBString::create($res['schedule_date']);
        $this->track_count = DBTrackCount::create($res['track_count']);
        $this->length = DBLength::create($res['length']);
        $this->tba = DBBoolean::create($res['tba']);
        $this->has_picture = DBBoolean::create($res['has_picture']);
        $this->record_type = DBString::create($res['record_type']);
        $this->record_type_id = DBRecordTypeId::create($res['record_type_id']);
        $this->picture_path = DBString::create($res['picture_path']);
        $this->artist_name = DBString::create($res['artist_name']);
        $this->label_name = DBString::create($res['label_name']);
        $this->leaked = DBBoolean::create($res['leaked']);

        return true;
    }

    public function __set($name, $value) {

        $value = trim($value);

        // validation
        switch($name) {
            case 'name':
                if(strlen($value) > MAX_RELEASE_NAME_LENGTH)
                    throw new Exception(_('Release name can be ').MAX_RELEASE_NAME_LENGTH._(' characters max.'));

                if(strlen($value) == 0)
                    throw new Exception(_('Release name must not be empty.'));

                break;

            case 'year_started':
            case 'year_finished':
                if(strlen($value) > 0 && !preg_match('/^[0-9]{4}$/', $value))
                    throw new Exception(_('Invalid year format: ') . $value);

                break;

            case 'release_date':
                /*if(!preg_match('/^[\d]{4}\-[\d]{2}\-[\d]{2}$/', $value))
                    throw new Exception('Invalid date format: ' . $value);

                $data = explode('-', $value);

                if(!checkdate($data[1], $data[2], $data[0]))
                    throw new Exception('Invalid date: ' . $value);*/
                if(!preg_match('/^[\d]{4}\-[\d]{2}\-[\d]{2}$/', $value)) {

                    $this->schedule_date = $value;
                    return;

                } else {

                    $data = explode('-', $value);
                    if(!checkdate($data[1], $data[2], $data[0]))
                        throw new Exception(_('Invalid date: ') . $value);

                    if(strtotime($value) > strtotime(date('Y-m-d'))) {
                        $this->schedule_date = $value;
                        return;

                    } else {
                        $this->year_finished = $data[0];
                        $this->schedule_date = NULL;
                        $this->leaked = true;
                    }

                }

                break;

            case 'schedule_date':
                if(strlen($value) > MAX_RELEASE_SCHEDULE_DATE_LENGTH)
                    throw new Exception(_('Schedule date can be ').MAX_RELEASE_SCHEDUKE_DATE_LENGTH._(' characters max.'));

                break;

            case 'track_count':
                if(strlen($value) > 0 && !preg_match('/^[\d]+$/', $value))
                    throw new Exception(_('Invalid track count: ') . $value);

                break;

            case 'length':
                if(strlen($value) > 0 && !preg_match('/^[\d]+$/', $value))
                    throw new Exception(_('Invalid length format: ') . $value);

                break;

            case 'record_type_id':
                if(strlen($value) > 0 &&
                    $this->dbo->getOne('SELECT COUNT(*)
                        FROM mtl.record_types
                        WHERE id = ?',
                        array(
                            DBInteger::create($value)
                        )) == 0
                )
                    throw new Exception(_('Invalid record type: '). $value);

                break;

            case 'tba':
                if($value === true)
                    $this->name = 'To be announced';

                break;
        }
        parent::__set($name, $value);
    }

    public function __get($name) {

        return parent::__get($name);
    }

    public function save() {

        //if(!$this->changed && $this->loaded)
        //    return true;

        if(!is_null($this->id)) {

            $res = $this->dbo->query("UPDATE $this->table SET
                name=?,
                year_started=?,
                year_finished=?,
                release_date=?,
                schedule_date=?,
                track_count=?,
                length=?,
                tba=?,
                has_picture=?,
                record_type_id=?,
                picture_path=?,
                leaked=?
                WHERE id=?",
                array(
                    DBString::create($this->name),
                    DBYear::create($this->year_started),
                    DBYear::create($this->year_finished),
                    DBDate::create($this->release_date),
                    DBString::create($this->schedule_date),
                    DBTrackCount::create($this->track_count),
                    DBLength::create($this->length),
                    DBBoolean::create($this->tba),
                    DBBoolean::create($this->has_picture),
                    DBRecordTypeId::create($this->record_type_id),
                    DBString::create($this->picture_path),
                    DBBoolean::create($this->leaked),
                    DBInteger::create($this->id)
                ));

            throwOnError($res);

            if($res != DB_OK)
                throw new Exception(_('Failed to save release.'));

        } else {

            parent::save(__CLASS__);
            $this->save();
        }

        return $this->id;
    }
    
    public function isWatchedByUser($user_id) {

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.watch_releases
            WHERE user_id = ? AND release_id=?",
            array(
                DBInteger::create($user_id),
                DBInteger::create($this->id)
            ),
            DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return ($res > 0);
    }

    public function getComments() {

        $res = $this->dbo->getAll("SELECT
            com.id,
            date_trunc('second', com.date_added) as date_added,
            u.name as user_name,
            com.added_by_user_id as user_id,
            u.picture_path,
            com.message
         FROM mtl.releases_comments com
         LEFT JOIN sys.users u ON (u.id = com.added_by_user_id)
         WHERE com.release_id = ?
         ORDER BY com.id DESC",
        array(
            DBInteger::create($this->id)
        ),
        DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return $res;
    }

    public function addComment($message, $user_id) {

        $res = $this->dbo->query("SELECT mtl.add_release_comment(?,?,?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($user_id),
                DBComment::create($message),
                DBString::create($_SERVER['REMOTE_ADDR'])
            ));

        throwOnError($res);

        return true;
    }

    public function linkWithLabel($id) {

        $res = $this->dbo->query("SELECT mtl.link_release_with_label(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($id)
            ));

        throwOnError($res);

        return true;
    }

    public function linkedWithLabel($name) {

        if(!Label::exists($name))
            return false;

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.releases_rel_label rel
            LEFT JOIN mtl.labels l ON (rel.label_id = l.id)
            WHERE rel.release_id = ? AND LOWER(l.name) = LOWER(?)",
            array(
                DBInteger::create($this->id),
                DBString::create($name)
            ));

        throwOnError($res);

        return ($res > 0);
    }

    public function uploadPicture($file) {

        $picture_path = $this->name . " " . $this->id;
        $picture_path = str_replace(" ", "_", $picture_path);
        $picture_path = ereg_replace("[^A-Za-z0-9\_]", "", $picture_path);

        $db_path = '/'.RELEASES_THUMB_DIR . $picture_path;

        $picture_path = $_SERVER['DOCUMENT_ROOT'] . RELEASES_THUMB_DIR . $picture_path;

        $result_path = Picture::upload($file, $picture_path);

        Picture::generateThumbnail($result_path, RELEASES_THUMB_WIDTH, RELEASES_THUMB_HEIGHT);

        $this->picture_path = $db_path . '.' . end(explode('.', $result_path));

        $this->save();

        return true;
    }

    public function uploadPictureFromUrl($url) {

        $picture_path = $this->name . " " . $this->id;
        $picture_path = str_replace(" ", "_", $picture_path);
        $picture_path = ereg_replace("[^A-Za-z0-9\_]", "", $picture_path);

        $db_path = '/'.RELEASES_THUMB_DIR . $picture_path;

        $picture_path = $_SERVER['DOCUMENT_ROOT'] . RELEASES_THUMB_DIR . $picture_path;

        $result_path = Picture::uploadFromUrl($url, $picture_path);

        Picture::generateThumbnail($result_path, RELEASES_THUMB_WIDTH, RELEASES_THUMB_HEIGHT);

        $this->picture_path = $db_path . '.' . end(explode('.', $result_path));

        $this->save();

        return true;
    }

    public function markAsLeaked($flag) {

        if($flag) {
            $this->dbo->query('SELECT mtl.mark_leaked(?)', array(DBInteger::create($this->id)));
        } else {
            $this->dbo->query('SELECT mtl.mark_unleaked(?)', array(DBInteger::create($this->id)));
        }
    }

    public static function create($name) {

        return parent::create($name, __CLASS__);
    }

    public static function exists($name, $year) {

        $dbo = DBO::getInstance();
        //return parent::exists($name, __CLASS__);
        $res = $dbo->getOne("SELECT COUNT(*)
            FROM mtl.releases
            WHERE name = ? AND year_finished = ?",
            array(
                DBString::create($name),
                DBInteger::create($year)
            ));

        throwOnError($res);

        return (boolean)($res > 0);
    }

}